#ifndef _ANALYSIS_HPP
#define	_ANALYSIS_HPP

#include "ast.hpp"
#include "parser.hpp"

#include<iostream>
#include <unordered_map>


namespace analysis
{
  
using std::ostream;
using std::endl;
using std::unordered_map;

using namespace ast;


class Pass {
public:
  Pass(ostream&);

  void emit_warning(const ast::Node& node, const char* msg);
  void emit_error(const ast::Node& node, const char* msg);

  bool succeeded();

protected:
  ostream& out;
  bool has_errors;
};


class SemanticCheckPass : public Visitor, public Pass {
public:
  SemanticCheckPass(ostream&);

  void visit(Program&);
  void visit(Directive&);
  void visit(Instruction&);
  void visit(Operand&);
};


struct SymbolInfo {
  SymbolInfo();
  SymbolInfo(int _offset);

  bool is_defined() const;

  bool is_global;
  bool is_extern;
  bool is_code;
  int offset;
};


class SymbolTable : public unordered_map<Label, SymbolInfo> {
public:
  bool contains(const Label& label) const;

  int dataSize;
  int textSize;
};


class SymbolTableBuildPass : public Visitor, public Pass {
public:
  SymbolTableBuildPass(ostream&);

  void visit(Program&);

  void visit(DataSection&);
  void visit(TextSection&);

  void visit(Directive&);
  void visit(Instruction&);

  SymbolTable symbol_table;
  Label* startLabel;

  int textOffset;
  int dataOffset;

protected:
  void normalize_label(Label& label);
  void process_labels(LabelList& labels, uint offset, bool is_code);

  Label topLabel;
  Node* currentNode;
};


class SymbolResolverPass : public Visitor, public Pass {
public:
  SymbolResolverPass(ostream&, SymbolTable&, int, int, Label&);

  void visit(Program&);
  void visit(Directive&);
  void visit(Instruction&);

  int startOffset();

protected:
  void resolve_global_symbols();

  Label demangle_label(const Label&);
  bool equal_labels(const Label&, const Label&);

  SymbolTable& symbol_table;
  Label& startLabel;
  Node* currentNode;

  unordered_map<Label,Label> globals;
};


}


#endif
